<?php

namespace app\wechat\controller;

use app\common\model\Assistant;
use app\common\model\DutyRecord;
use app\common\model\DutyArrange;
use DateTime;
use DateInterval;

class Index extends \think\Controller
{

    const signSalt = "this is salt";
    /**
     *
     * 对接微信服务器,该方法接受的是GET请求
     */
    public function registerServer()
    {
        $request = $this->request;
        $tmpArray = array(config('wechat.token'), $request->param('timestamp'), $request->param('nonce'));
        sort($tmpArray, SORT_STRING);
        $tmpStr = implode("", $tmpArray);
        $tmpStr = sha1($tmpStr);

        if ($request->param('signature') == $tmpStr) {
            echo $request->param('echostr');
        } else {
            echo "验证不通过";
        }
    }

    /**
     * 微信服务器推送消息入口,该方法接受的是POST请求
     *
     * @return void
     */
    public function handler()
    {
        $HTTP_RAW_POST_DATA = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
        $table = $this->parseMessage($HTTP_RAW_POST_DATA);

        if ($table['MsgType'] == 'text') {
            switch ($table['Content']) {
                case '开门表':
                    return $this->responseTextMessage($this->genLink('web', "打开日开门统计表"), $table);
                case '签到':
                case '签退':
                    $time = time();
                    $sign = MD5($table['FromUserName'] . Index::signSalt . $time);
                    return $this->responseTextMessage($this->genLink('index.php/wechat/open_sign_in?wechat_id=' . $table['FromUserName'] . "&time=" . $time . "&sign=" . $sign, '点击进行签到'), $table);
                default:
                    $match = array();
                    if (preg_match("/绑定(.*)/", $table['Content'], $match)) {
                        $res = Assistant::where('openid', $table['FromUserName'])->find();
                        if ($res) {
                            return $this->responseTextMessage("您已绑定了助理:" . $res->name . ",无法重复绑定,如果属于操作有误,请联系管理员重置助理数据", $table);
                        }
                        if (strlen($match[1])) {
                            $res = Assistant::where('name', $match[1])->find();
                            if ($res) {
                                if (isset($res->openid) && strlen($res->openid) == 32) {
                                    return $this->responseTextMessage($match[1] . "已经绑定了微信号,请联系管理员清理数据后重新绑定", $table);
                                } else {
                                    $res->save(['openid' => $table['FromUserName']]);
                                    return $this->responseTextMessage('已成功绑定助理"' . $match[1] . '"', $table);
                                }
                            } else {
                                return $this->responseTextMessage('找不到助理"' . $match[1] . '"的信息,请联系管理员进行数据导入', $table);
                            }
                        } else {
                            return $this->responseTextMessage("请输入\"绑定+助理姓名\"来完成绑定\n例如输入:绑定张三", $table);
                        }
                    } else if (preg_match("/(.*)值班助理/", $table['Content'], $match)) {
                        switch ($match[1]) {
                            case "今日":
                            case "今天":
                                $date = date_create();
                                break;
                            case "前天":
                            case "前日":
                                $date = date_sub(date_create(), new DateInterval("P2D"));
                                break;
                            case "昨天":
                            case "昨日":
                                $date = date_sub(date_create(), new DateInterval("P1D"));
                                break;
                            case "明天":
                            case "明日":
                                $date = date_add(date_create(), new DateInterval("P1D"));
                                break;
                            case "后天":
                                $date = date_add(date_create(), new DateInterval("P1D"));
                                break;
                                case "":
                                return $this->responseTextMessage("请输入'日期'+'值班助理'关键字完成查询\n例如:今日值班助理、昨日值班助理、2019/7/1值班助理等等", $table);
                                break;
                            default:
                                if (preg_match("/(?:\d{4}[\/])?\d{1,2}[\/]\d{1,2}|(?:\d{4}年)?\d{1,2}月\d{1,2}日/", $match[1])) {
                                    $date = date_create($match[1]);
                                    break;
                                } else {
                                    return $this->responseTextMessage('指定的日期有误'.$match[1], $table);
                                }
                        }
                        $date = date_format($date, 'Y-m-d');
                        $arrangeModel = new DutyArrange;
                        $res = $arrangeModel->getDutyAssistantDetial($date, null);
                        if ($res) {
                            $ret = [];
                            foreach ($res as $v) {
                                $ret[] = "姓名:" . $v['name'] . "\n班级:" . $v['class_name'] . "\n节次:" . $v['duty_classtime'] . "\n电话:" . $v['phone']."\n教学楼:".$v['building'];
                            }
                            return $this->responseTextMessage($date . "值班人员信息如下:\n" . implode("\n\n", $ret), $table);
                        } else {
                            return $this->responseTextMessage($date . '未安排助理值班', $table);
                        }
                    }
            }
        }
        return $this->responseTextMessage(
            "很抱歉,暂时无法识别此指令\n" .
                "暂时能够识别的指令有:绑定、开门表、签到、值班助理",
            $table
        );
    }
    //*************************** 业务代码 *****************************

    /**
     * 打开签到界面
     *
     * @return void
     */
    public function openSignIn()
    {
        try {
            $request = $this->request;
            $config = $this->genWebPageConfig($request->url(true));
            $wechat_id = $request->param("wechat_id");
            $time = $request->param("time");
            $sign = $request->param("sign");

            if (time() - $time > 3600 * 6) {
                return $this->error("此URL已过期");
            }

            if (md5($wechat_id . Index::signSalt . $time) !== $sign) {
                return $this->error("此URL无效");
            }

            $config['wechat_id'] = $wechat_id;
            $assistantModel = Assistant::where("openid", $config['wechat_id'])->find();

            if ($assistantModel) {
                $dutyRecord = new DutyRecord;
                if ($record = $dutyRecord->checkSignOut($assistantModel->id)) {
                    $config['isSignIn'] = 'false';
                    $config['signInTime'] =  $record->start_time;
                } else {
                    $config['isSignIn'] = 'true';
                    $config['signInTime'] = "未签到";
                }
                $config['name'] = $assistantModel->name;
                $config['akey'] = $assistantModel->getAKey();
                return $this->fetch('signinout', $config);
            } else {
                return $this->error("当前微信未绑定助理信息,请先完成绑定");
            }
        } catch (\Exception $err) {
            throw $err;
            return $this->error("打开网页异常\n" . $err->getMessage());
        }
    }

    //************************** 内部API ********************************

    /**
     * 生成供前端访问的URL
     */
    private function genLink($api, $label)
    {
        return sprintf('<a href="http://%s/%s">%s</a>', config('app_host'), $api, $label);
    }
    /**
     * 解析接收的消息为table
     */
    private function parseMessage($xmlData)
    {
        $document = new \DOMDocument;
        $document->loadXML($xmlData);
        $table = [];
        $table['ToUserName'] = trim($document->getElementsByTagName('ToUserName')->item(0)->nodeValue);
        $table['FromUserName'] = trim($document->getElementsByTagName('FromUserName')->item(0)->nodeValue);
        $table['CreateTime'] = $document->getElementsByTagName('CreateTime')->item(0)->nodeValue;
        $table['MsgType'] = trim($document->getElementsByTagName('MsgType')->item(0)->nodeValue);
        $table['Content'] = trim($document->getElementsByTagName('Content')->item(0)->nodeValue);
        $table['MsgId'] = $document->getElementsByTagName('MsgId')->item(0)->nodeValue;
        return $table;
    }

    /**
     * 用于回复消息
     */
    private function responseTextMessage($data, $reqTable)
    {
        $format = "<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%d</CreateTime><MsgType><![CDATA[%s]]></MsgType><Content><![CDATA[%s]]></Content></xml>";
        return printf($format, $reqTable['FromUserName'], $reqTable['ToUserName'], time(), 'text', $data);
    }

    /**
     * 获取微信的access_token
     */
    private function getAccessToken()
    {
        $ret = cache("access_token");
        if (!$ret) {
            $appID = config('wechat.appID');
            $appSecret = config('wechat.appSecret');
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appID}&secret={$appSecret}";
            $ret = curl_get($url);
            if ($ret === false) {
                throw new \Exception("后台无法访问微信服务器");
            }
            $ret = json_decode($ret, 1);
            if (isset($ret['errcode']) && $ret['errcode'] != 0) {
                throw new \Exception($ret['errmsg']);
            }
            cache("access_token", $ret, 3600);
        }

        return $ret['access_token'];
    }

    /**
     * 获取js-sdk调用门票
     */
    private function getJSApiTicket()
    {
        $ret = cache("jsapi_ticket");
        if (!$ret) {
            $accessToken = $this->getAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={$accessToken}&type=jsapi";
            $ret = curl_get($url);
            if ($ret === false) {
                throw new \Exception("后台无法访问微信服务器");
            }
            $ret = json_decode($ret, 1);
            if ($ret['errcode'] != 0) {
                throw new \Exception($ret['errmsg']);
            }
            cache("jsapi_ticket", $ret, 3600);
        }
        return $ret['ticket'];
    }

    /**
     * 生成网页上API的配置信息
     */
    private function genWebPageConfig($url)
    {
        $noncestr = getRandomStr(16);
        $ticket = $this->getJSApiTicket();
        $time = time();

        $table = ['noncestr' => $noncestr, 'jsapi_ticket' => $ticket, 'timestamp' => $time, 'url' => $url];
        ksort($table, SORT_STRING);
        $tmpTable = [];
        foreach ($table as $k => $v) {
            $tmpTable[] = $k . '=' . $v;
        }
        $tmpStr = implode('&', $tmpTable);
        $signature = sha1($tmpStr);

        return [
            'appId' => config('wechat.appID'),
            'timestamp' => $time,
            'nonceStr' => $noncestr,
            'signature' => $signature,
        ];
    }
}
